import os
import uuid
from datetime import datetime

from django.contrib.auth import authenticate
from django.contrib.auth.hashers import make_password
from django.contrib.auth.models import update_last_login
from django_restql.fields import DynamicSerializerMethodField
from rest_framework import serializers
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from common.models.system import Dictionary, Users, Role, Menu, MenuButton, OperationLog, Dept
from settings import conf
from utils.file_name import Encrypt
from utils.serializers import CustomModelSerializer
from utils.validator import CustomUniqueValidator


class DeptSerializer(CustomModelSerializer):
    class Meta:
        model = Dept
        fields = '__all__'
        read_only_fields = ['id']


class DictionarySerializer(CustomModelSerializer):
    """字典-序列化器"""
    class Meta:
        model = Dictionary
        fields = '__all__'
        read_only_fields = ['id']


class DictionaryInitSerializer(CustomModelSerializer):
    """初始化获取数信息(用于生成初始化json文件)"""
    children = serializers.SerializerMethodField()

    def get_children(self, obj: Dictionary):
        data = []
        instance = Dictionary.objects.filter(parent_id=obj.id)
        if instance:
            serializer = DictionaryInitSerializer(instance=instance, many=True)
            data = serializer.data
        return data

    def save(self, **kwargs):
        instance = super().save(**kwargs)
        children = self.initial_data.get('children')
        # 菜单表
        if children:
            for data in children:
                data['parent'] = instance.id
                filter_data = {
                    'value': data['value'],
                    'parent': data['parent']
                }
                instance_obj = Dictionary.objects.filter(**filter_data).first()
                if instance_obj and not self.initial_data.get('reset'):
                    continue
                serializer = DictionaryInitSerializer(instance_obj, data=data, request=self.request)
                serializer.is_valid(raise_exception=True)
                serializer.save()
        return instance

    class Meta:
        model = Dictionary
        fields = ['label', 'value', 'parent', 'type', 'color', 'is_value',
                  'status', 'sort', 'remark', 'creator', 'children']
        read_only_fields = ['id']
        extra_kwargs = {'creator': {'write_only': True}}


# class FileSerializer(CustomModelSerializer):
#
#     class Meta:
#         model = FileList
#         fields = '__all__'
#
#     def validate(self, validated_data):
#         file_data = self.initial_data.get('file')
#         if not file_data:
#             raise serializers.ValidationError('请上传文件')
#         validated_data['file'] = file_data
#         return validated_data
#
#     def create(self, validated_data):
#         validated_data['name'] = str(validated_data['file'])
#         md5 = hashlib.md5()
#         for chunk in validated_data['file'].chunks():
#             md5.update(chunk)
#         validated_data['md5sum'] = md5.hexdigest()
#         # md5值相同认为是同一个文件，不再上传
#         old = FileList.objects.filter(md5sum=validated_data['md5sum']).first()
#         if old:
#             return old
#         validated_data['url'] = upload_file(validated_data['file'])
#         del validated_data['file']
#         return super().create(validated_data)


class MenuSerializer(CustomModelSerializer):
    """菜单表的简单序列化器"""
    menu_permission = serializers.SerializerMethodField(read_only=True)
    has_child = serializers.SerializerMethodField()

    def get_menu_permission(self, instance):
        queryset = instance.menu_permission.order_by('-name').values_list('name', flat=True)
        if queryset:
            return queryset
        else:
            return None

    def get_has_child(self, instance):
        has_child = Menu.objects.filter(parent=instance.id)
        if has_child:
            return True
        return False

    class Meta:
        model = Menu
        fields = '__all__'
        read_only_fields = ['id']


class MenuCreateSerializer(CustomModelSerializer):
    """菜单表的创建序列化器"""
    name = serializers.CharField(required=False)

    class Meta:
        model = Menu
        fields = '__all__'
        read_only_fields = ['id']


class WebRouterSerializer(CustomModelSerializer):
    """前端菜单路由的简单序列化器"""
    path = serializers.CharField(source='web_path')
    title = serializers.CharField(source='name')
    menu_permission = serializers.SerializerMethodField(read_only=True)

    def get_permission_ids(self):
        if hasattr(self, 'permission_ids'):
            return self.permission_ids
        permission_ids = self.request.user.role.values_list('permission', flat=True)
        setattr(self, 'permission_ids', permission_ids)
        return permission_ids

    def get_menu_permission(self, instance):
        if instance.is_catalog or instance.is_link:
            return None

        # role_admin = self.get_role_admin_flag()
        # 超管和管理员角色拥有所有按钮权限
        if self.request.user.is_superuser:
            return instance.menu_permission.values_list('value', flat=True)
        else:
            # 根据当前角色获取权限按钮id集合
            permission_ids = self.get_permission_ids()
            queryset = instance.menu_permission.filter(
                id__in=permission_ids, menu=instance.id).values_list('value', flat=True)
            if queryset:
                return queryset
            else:
                return None

    class Meta:
        model = Menu
        fields = ('id', 'parent', 'icon', 'sort', 'path', 'name', 'title', 'is_link', 'is_catalog',
                  'web_path', 'component', 'component_name', 'cache', 'visible', 'menu_permission')
        read_only_fields = ['id']


class MenuPermissonSerializer(WebRouterSerializer):
    """菜单的按钮权限"""

    def get_menu_permission(self, instance):
        if instance.is_catalog or instance.is_link:
            return None

        # role_admin = self.get_role_admin_flag()
        # 超管和管理员角色拥有所有按钮权限
        if self.request.user.is_superuser:
            queryset = MenuButton.objects.filter(menu__id=instance.id)
        else:
            menu_permission_id_list = self.request.user.role.values_list('permission', flat=True)
            queryset = MenuButton.objects.filter(id__in=menu_permission_id_list, menu__id=instance.id)
        serializer = MenuButtonSerializer(queryset, many=True, read_only=True)
        return serializer.data

    class Meta:
        model = Menu
        fields = ['id', 'parent', 'name', 'menu_permission', 'sort']


class MenuButtonSerializer(CustomModelSerializer):
    """菜单按钮-序列化器"""

    class Meta:
        model = MenuButton
        fields = ['id', 'name', 'value', 'api', 'method', 'menu']
        read_only_fields = ['id']


class MenuButtonCreateUpdateSerializer(CustomModelSerializer):
    """初始化菜单按钮-序列化器"""

    class Meta:
        model = MenuButton
        fields = '__all__'
        read_only_fields = ['id']


class OperationLogSerializer(CustomModelSerializer):
    """日志-序列化器"""
    creator_name = serializers.SlugRelatedField(
        slug_field='name', source='creator', read_only=True)

    class Meta:
        model = OperationLog
        fields = '__all__'
        read_only_fields = ['id']


class RoleSerializer(CustomModelSerializer):
    """角色-序列化器"""

    class Meta:
        model = Role
        fields = '__all__'
        read_only_fields = ['id']


class RoleCreateUpdateSerializer(CustomModelSerializer):
    """角色管理 创建/更新时的列化器"""
    menu = MenuSerializer(many=True, read_only=True)
    dept = DeptSerializer(many=True, read_only=True)
    permission = MenuButtonSerializer(many=True, read_only=True)
    name = serializers.CharField(
        max_length=50, validators=[CustomUniqueValidator(queryset=Role.objects.all(), message='角色名称已存在')])

    def save(self, **kwargs):
        # is_superuser = self.request.user.is_superuser
        # if not is_superuser:
        #     self.validated_data.pop('admin')
        data = super().save(**kwargs)
        data.dept.set(self.initial_data.get('dept', []))
        menu_ids = self.initial_data.get('menu', [])
        permission_ids = self.initial_data.get('permission', [])
        # 添加关联内页
        menus = Menu.objects.filter(
            parent_id__in=menu_ids, status=True, visible=False).values_list('id', flat=True)
        menu_ids.extend(menus)
        # 添加关联内页权限
        permissions = MenuButton.objects.filter(menu_id__in=menus).values_list('id', flat=True)
        permission_ids.extend(permissions)
        # 保存菜单和权限
        data.menu.set(menu_ids, clear=True)
        data.permission.set(permission_ids, clear=True)
        return data

    class Meta:
        model = Role
        fields = '__all__'


class UserSerializer(CustomModelSerializer):
    """用户管理-序列化器"""
    roles = DynamicSerializerMethodField()

    class Meta:
        model = Users
        read_only_fields = ['id']
        exclude = ['password']
        extra_kwargs = {
            'post': {'required': False},
        }

    def get_roles(self, instance, parsed_query):
        roles = instance.role.all()
        serializer = RoleSerializer(
            roles,
            many=True,
            parsed_query=parsed_query
        )
        return serializer.data


class UserCreateSerializer(CustomModelSerializer):
    """用户新增-序列化器"""
    username = serializers.CharField(
        max_length=50,
        validators=[
            CustomUniqueValidator(queryset=Users.objects.all(), message='账号已存在')
        ],
    )

    def validate_password(self, value):
        """对密码进行验证"""
        password = self.initial_data.get('password')
        if password:
            return make_password(value)
        return value

    def validate(self, validated_data):
        validated_data['dept_belong_id'] = validated_data['dept_id']
        return validated_data

    class Meta:
        model = Users
        fields = '__all__'
        read_only_fields = ['id']


class UserUpdateSerializer(CustomModelSerializer):
    """用户修改-序列化器"""
    mobile = serializers.CharField(max_length=50, allow_blank=True)

    class Meta:
        model = Users
        read_only_fields = ['id', 'password', 'username']
        fields = '__all__'


class LoginSerializer(TokenObtainPairSerializer, ):
    """ 登录的序列化器: 重写djangorestframework-simplejwt的序列化器"""

    class Meta:
        model = Users
        fields = '__all__'
        read_only_fields = ['id']

    def validate(self, attrs):
        authenticate_kwargs = {
            self.username_field: attrs[self.username_field],
            'password': attrs['password'],
        }
        try:
            authenticate_kwargs['request'] = self.context['request']
        except KeyError:
            pass

        user = authenticate(**authenticate_kwargs)
        if not user:
            raise serializers.ValidationError('账号或密码错误')
        if not user.is_active:
            raise serializers.ValidationError('账号被禁用')
        # if user.type != '1':
        #     raise serializers.ValidationError('用户不存在')

        data = self.get_login_info(user)
        update_last_login(None, user)
        return {'code': 2000, 'msg': '请求成功', 'data': data}

    @staticmethod
    def get_login_info(user):
        data = dict()
        refresh = TokenObtainPairSerializer.get_token(user)
        # data['refresh'] = str(refresh)
        data['access'] = str(refresh.access_token)
        data['name'] = user.name
        data['user_id'] = user.id
        data['avatar'] = user.avatar
        data['dept_id'] = user.dept_id
        data['roles'] = user.role.values('id', 'name')
        return data


class ReportRecordUploadSerializer(serializers.Serializer):
    file = serializers.FileField(max_length=1024 * 1024 * 50,  # 限制文件最大50MB
                                 allow_empty_file=False,
                                 use_url=False)
    file_path = serializers.SerializerMethodField(read_only=True)
    real_file_path = serializers.SerializerMethodField(read_only=True)

    def get_file_path(self, obj):
        return getattr(self, '_file_path', '')

    def get_real_file_path(self, obj):
        # return Encrypt().decrypted(self.get_file_path(obj))
        return getattr(self, '_reps_file_path', '')

    def validate(self, validated_data):
        # 导入文件保存到本地
        file = self.initial_data.get('file')
        allow_file = ('.png', '.jpg', '.jpeg', '.xlsx', '.xls', '.csv')
        if not file.name.endswith(allow_file):
            raise serializers.ValidationError('文件格式错误,支持文件类型{}'.format(" ".join(allow_file)))
        converted_date = datetime.today().strftime('%Y%m%d')
        file_dir = os.path.join(conf.STATIC_ROOT, 'upload/{}'.format(converted_date))
        if not os.path.exists(file_dir):
            os.makedirs(file_dir)
        file_name = '{0}_{1}'.format(uuid.uuid4(), file.name)
        file_path = os.path.join(file_dir, file_name)
        with open(file_path, 'wb+') as destination:
            for chunk in file.chunks():
                destination.write(chunk)
        reps_file_path = 'upload/{}'.format(converted_date) + '/' + file_name
        self._file_path = Encrypt().cipher(reps_file_path)
        self._reps_file_path = reps_file_path
        return validated_data
